package com.example.controller;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dashscope.app.Application;
import com.alibaba.dashscope.app.ApplicationParam;
import com.alibaba.dashscope.app.ApplicationResult;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.example.common.enums.ResultCodeEnum;
import com.example.common.exception.BusinessException;
import com.example.domain.User;
import com.example.domain.dto.ChatMessageDto;
import com.example.domain.vo.ChatMessageVo;
import com.example.domain.vo.Result;
import com.example.service.AIToolService;
import com.example.service.WebService;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.util.List;

@RestController
@RequestMapping("/front/culture/AITool")
@Slf4j
public class AIToolController {
    @Autowired
    private AIToolService aiToolService;
    @Autowired
    private WebService webService;
    @Value("${web.points}")
    private Long points;

    @PostMapping("/dialogue")
    public Result addDialogue(@RequestBody ChatMessageDto chatMessageDto) {
        aiToolService.addDialogue(chatMessageDto);
        return Result.success(chatMessageDto);
    }

    @DeleteMapping("/dialogue/{dialogueId}")
    public Result deleteDialogue(@PathVariable Long dialogueId) {
        aiToolService.deleteDialogue(dialogueId);
        return Result.success();
    }

    @GetMapping("/dialogue/{userId}/{dialogueTitle}")
    public Result getDialogueById(@PathVariable Long userId, @PathVariable String dialogueTitle) {
        List<ChatMessageVo> list = aiToolService.getDialogueById(userId, dialogueTitle);
        return Result.success(list);
    }

    @GetMapping("/ChatMessage/{dialogueId}")
    public Result getChatMessage(@PathVariable Long dialogueId) {
        List<ChatMessageVo> list = aiToolService.getDialogueByDialogueId(dialogueId);
        return Result.success(list);
    }

    /**
     * TODO 需要根据对话的上下文来回答
     * 处理聊天请求，实现与通义-Max的流式交互。
     * 需要对话id 信息内容
     *
     * @param chatMessageDto
     * @return
     */
    @PostMapping(value = "/ChatMessage", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<StreamingResponseBody> addChatMessage(@RequestBody ChatMessageDto chatMessageDto) {
        // 添加聊天需要对话id
        if (ObjectUtil.isEmpty(chatMessageDto.getDialogueId())) {
            throw new BusinessException(ResultCodeEnum.SYSTEM_ERROR);
        }

        User user = aiToolService.getUserById(chatMessageDto.getCreateUserId());

        if (user.getPoints() == 0 || user.getPoints() < 10) {
            throw new BusinessException(ResultCodeEnum.USER_POINTS_ERROR);
        }

        user.setPoints(user.getPoints() - points);
        webService.updateUser(user);

        // 用户信息先存储
        ChatMessageDto chatMessage = new ChatMessageDto();
        chatMessage.setDialogueId(chatMessageDto.getDialogueId());
        chatMessage.setMessageType("user");
        chatMessage.setContent(chatMessageDto.getContent());
        aiToolService.addChatMessage(chatMessage);

        return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(outputStream -> {
                    try {
                        // 在构建param前添加历史查询
                        List<ChatMessageVo> history = aiToolService.getDialogueByDialogueId(Long.valueOf(chatMessageDto.getDialogueId()));
                        StringBuilder contextPrompt = new StringBuilder();
                        for (ChatMessageVo chatMessageVo : history) {
                            if ("user".equals(chatMessageVo.getMessageType())) {
                                contextPrompt.append(chatMessageVo.getContent());
                            }
                        }
                        // 构建应用参数
                        ApplicationParam param = ApplicationParam.builder()
                                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                                .appId("268c83f42290484b81019c4cb7ee53dc")
                                .prompt(String.valueOf(contextPrompt))
                                .incrementalOutput(true)
                                .build();

                        // 创建应用实例并发起流式调用
                        Application application = new Application();
                        Flowable<ApplicationResult> result = application.streamCall(param);

                        // 初始化机器人消息对象
                        ChatMessageDto robotChatMessage = new ChatMessageDto();
                        robotChatMessage.setMessageType("robot");
                        robotChatMessage.setContent("");
                        robotChatMessage.setDialogueId(chatMessageDto.getDialogueId());

                        // 处理流式返回的数据
                        result.blockingForEach(data -> {
                            // 获取每次返回的文本片段
                            String segment = data.getOutput().getText();
                            // 更新机器人消息内容并保存到数据库
                            robotChatMessage.setContent(robotChatMessage.getContent() + segment);
                            // 将文本片段写入输出流并刷新
                            outputStream.write((segment + "\n").getBytes());
                            outputStream.flush();
                        });
                        aiToolService.addChatMessage(robotChatMessage);
                    } catch (ApiException | NoApiKeyException | InputRequiredException e) {
                        // 捕获异常并记录错误消息
                        ChatMessageDto errorChatMessage = new ChatMessageDto();
                        errorChatMessage.setMessageType("error");
                        errorChatMessage.setContent("Exception: " + e.getMessage());
                        aiToolService.addChatMessage(errorChatMessage);
                        // 将异常信息写入输出流并刷新
                        outputStream.write(("Exception: " + e.getMessage() + "\n").getBytes());
                        outputStream.flush();
                    } finally {
                        // 关闭输出流
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
    }
}
